﻿using System.Windows.Forms;
using Microsoft.SharePoint;
using System;
using System.IO;
using System.Collections;
using System.Xml;
using System.Data;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
namespace ContentMigrator
{
    public class StaticMethods
    {
        public struct FTPInfo
        {
            public string Server;
            public int Port;
            public string User;
            public string Password;
            public string Path;
        }

        public static frmFileSystem frmFileSystem1 = null;
        public static frmNewDB frmNewDB1 = null;
        public static frmLoadMetabase frmLoadMetabase1 = null;
        public static frmConvertAccess frmConvertAccess1 = null;
        public static frmMain frmMainRef = null;
        public static frmMetabaseImport frmMetabaseImport1 = null;
        public enum MetaField {Group1, Group2, Group3, Group4, DateCreated, Title, Filename, Description, FolderTree, Meta1, Meta2, Meta3, Meta4, Meta5, Meta6, Meta7, Meta8, Meta9, Meta10, Meta11, Meta12, Meta13, Meta14, Meta15, Meta16, Meta17, Meta18, Meta19, Meta20, Meta21, Meta22, Meta23, Meta24, Meta25 };
        public static void ExpandFolderToArrayList(string folder, ArrayList arl)
        {
            try
            {
                string[] entries = Directory.GetFileSystemEntries(folder);
                foreach (string myentry in entries)
                {
                    if (Directory.Exists(myentry))
                    {
                        //directory, call recursively
                        ExpandFolderToArrayList(myentry, arl);
                    }
                    else
                    {
                        //file
                        arl.Add(myentry);
                    }
                }

            }
            catch (Exception)
            {

                throw;
            }
        }
        public static SPFolder CreateFolder(SPWeb myweb, SPFolder parentfolder, string folderpath, string foldername)
        {
            try
            {
                //create it
                SPFolder folder = null;
                //, SPFileSystemObjectType.Folder, null
                SPFolder newfolder = parentfolder.SubFolders.Add(foldername);
                if (newfolder != null)
                {
                    newfolder.Item["Name"] = foldername;
                    newfolder.Update();
                }
                folder = myweb.GetFolder(folderpath);

                if (!folder.Exists)
                    throw new Exception("Could not create " + folderpath);

                return folder;
            }
            catch (Exception ex)
            {

                throw new Exception("CreateFolder:" + ex.Message);
            }
        }
        public static SPFolder GetFolderTree(SPWeb myweb,SPList mylib, string mytree, bool create)
        {
            try
            {
                char divider;
                SPFolder folder = null;
                SPFolder lastfolder = mylib.RootFolder;

                if (mytree.Contains("/"))
                    divider = '/';
                else
                    divider = '\\';

                if (mytree.EndsWith(divider.ToString()))
                    mytree = mytree.Substring(0, mytree.Length - 1);

                string[] folders = mytree.Split(divider);

                foreach (string myfolder in folders)
                {
                    string foldername = CleanFilename(myfolder);
                    string fullpath = lastfolder.ServerRelativeUrl + "/" + foldername;
                    
                    folder = mylib.ParentWeb.GetFolder(fullpath);
                    if (!folder.Exists)
                    {
                        if (create == true)
                        {
                            folder = StaticMethods.CreateFolder(myweb,lastfolder, fullpath, foldername);
                            lastfolder = folder;
                        }
                        else
                        {
                            throw new Exception("Folder '" + folder + "' not found and not created");
                        }
                    }
                    else
                    {
                        lastfolder = folder;
                    }
                }

                //return the last [deepest] folder created
                return lastfolder;
            }
            catch (Exception ex)
            {
                throw new Exception("GetFolderTree: " + ex.Message);
            }
        }
        public static byte[] GetFileBytes(string path)
        {
            try
            {
                if (path.ToLower().Contains("http"))
                {
                    WebClient wc = new WebClient();
                    wc.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                    return wc.DownloadData(path);
                }
                else if (path.ToLower().Contains("ftp"))
                {

                    FTPInfo info = ParseURL(path.ToLower());

                    string tempfile = System.Environment.CurrentDirectory + info.Path.Substring(info.Path.LastIndexOf("/") + 1);

                    FTP oFTP = new FTP();
                    oFTP.RemoteHost = info.Server;
                    oFTP.RemoteUser = info.User;
                    oFTP.RemotePass = info.Password;
                    oFTP.RemotePort = info.Port;

                    int last_slash_idx = info.Path.LastIndexOf("/");
                    if (last_slash_idx > -1)
                        oFTP.RemotePath = info.Path.Substring(0, last_slash_idx);
                    else
                        oFTP.RemotePath = "/";

                    oFTP.download(info.Path, tempfile);
                    if (!File.Exists(tempfile)) {
                        throw new Exception("FTP download failed: " + path);
                    }
                    byte[] file_bytes = File.ReadAllBytes(tempfile);
                    File.Delete(tempfile);
                    return file_bytes;
                }
                else
                {
                    //read from file system
                    return File.ReadAllBytes(path);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error downloading file " + path + ":" + ex.Message);
            }
        }
        public static FTPInfo ParseURL(string url)
        {

            try
            {
                FTPInfo info = new FTPInfo();
                string regexPattern = @"^(?<s1>(?<s0>[^:/\?#]+):)?(?<a1>"
                    + @"//(?<a0>[^/\?#]*))?(?<p0>[^\?#]*)"
                    + @"(?<q1>\?(?<q0>[^#]*))?"
                    + @"(?<f1>#(?<f0>.*))?";

                Regex re = new Regex(regexPattern, RegexOptions.ExplicitCapture);
                Match m = re.Match(url);

                System.Diagnostics.Debug.WriteLine("URL: " + url);

                info.Path = m.Groups["p0"].Value;
                string[] authority = m.Groups["a0"].Value.Split(':');

                if (authority.Length < 2)
                    throw new Exception("username:password@server not found in FTP URI");

                info.User = authority[0];
                string[] password_server = authority[1].Split('@');

                if (password_server.Length < 2)
                    throw new Exception("username:password@server not found in FTP URI");
                
                info.Password = password_server[0];
                info.Server = password_server[1];

                if (authority.Length > 2)
                    info.Port = Convert.ToInt32(authority[2]);
                else
                    info.Port = 21;

                System.Diagnostics.Debug.WriteLine(m.Groups["s0"].Value + "  (Scheme without colon)");
                System.Diagnostics.Debug.WriteLine(m.Groups["s1"].Value + "  (Scheme with colon)");
                System.Diagnostics.Debug.WriteLine(m.Groups["a0"].Value + "  (Authority without //)");
                System.Diagnostics.Debug.WriteLine(m.Groups["a1"].Value + "  (Authority with //)");
                System.Diagnostics.Debug.WriteLine(m.Groups["p0"].Value + "  (Path)");
                System.Diagnostics.Debug.WriteLine(m.Groups["q0"].Value + "  (Query without ?))");
                System.Diagnostics.Debug.WriteLine(m.Groups["q1"].Value + "  (Query with ?))");
                System.Diagnostics.Debug.WriteLine(m.Groups["f0"].Value + "  (Fragment without #)");
                System.Diagnostics.Debug.WriteLine(m.Groups["f1"].Value + "  (Fragment with #)");

                return info;

            }
            catch (Exception ex)
            {

                throw ex;
            }


        }
        public static void SetupGridDropdownColumn(DataColumnCollection mycol, DataGridViewComboBoxEditingControl mycb, bool clear)
        {
            try
            {
                if (clear == true)
                    mycb.Items.Clear();

                foreach (DataColumn myitem in mycol)
                {
                    mycb.Items.Add("@" + myitem.ColumnName);
                }
            }
            catch (Exception ex)
            {

                throw new Exception("SetupGridDropDownColumn[DataColumnCollection]:" + ex.Message);
            }
        }
        public static void SetupGridDropdownColumn(ICollection mycol, DataGridViewComboBoxEditingControl mycb, bool clear)
        {
            try
            {
                if (clear == true)
                    mycb.Items.Clear();

                foreach (object myitem in mycol)
                {
                    mycb.Items.Add(myitem.ToString());
                }
            }
            catch (Exception ex)
            {

                throw new Exception("SetupGridDropDownColumn[ICollection]:" + ex.Message);
            }
        }
        public static ArrayList GetFieldChoices(SPField myfield)
        {
            try
            {
                // use SchemaXml to determine characteristics of the question
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(myfield.SchemaXml);
                ArrayList ret = new ArrayList();

                if (myfield.Type == SPFieldType.Choice || myfield.Type == SPFieldType.MultiChoice)
                {
                    // drop-down listbox 
                    foreach (XmlNode node in xmlDoc.SelectNodes("//CHOICE"))
                    {
                        // choices from node.InnerText
                        ret.Add(node.InnerText);
                    }
                }
                return ret;
            }
            catch (Exception ex)
            {
                throw new Exception("GetFieldChoices:" + ex.Message);
            }
        }
        public static void EnumContentTypeFieldsToDataGridView(SPList mylib,string content_type_name, DataGridView dgv,Hashtable global_column_values)
        {
            try
            {
                int newrow = -1;
                ArrayList arlFieldCol = new ArrayList();
                ArrayList arlAddedFieldIDList = new ArrayList();

                if (content_type_name != string.Empty)
                {
                    //get content type fields
                    SPContentType ct = mylib.ContentTypes[content_type_name];
                    arlFieldCol.Add(ct.Fields);
                }

                //get non-content-type list fields in any case
                arlFieldCol.Add(mylib.Fields);

                dgv.Rows.Clear();
                // List all elegible fields in the field collection
                foreach (SPFieldCollection myfields in arlFieldCol)
                {      
                    foreach (SPField field in myfields)
                    {
                        System.Diagnostics.Debug.WriteLine(field.InternalName);
                        if (!(field.ReadOnlyField || field.Hidden || field.ReadOnlyField || field.InternalName.StartsWith("_") || arlAddedFieldIDList.Contains(field.Id)) || field.InternalName == "Name")
                        {
                            if (field.InternalName == "ContentType")
                            {
                                //set the value at the selected content type
                                newrow = dgv.Rows.Add(field.InternalName, content_type_name);

                                //make the row invisible
                                dgv.Rows[newrow].Visible = false;
                            }
                            else
                            {
                                newrow = dgv.Rows.Add(field.InternalName);
                            }
                            arlAddedFieldIDList.Add(field.Id);
                            System.Diagnostics.Debug.WriteLine(field.Id);

                            if (field.Type == SPFieldType.Choice || field.Type == SPFieldType.MultiChoice)
                            {
                                //populate choice values
                                ArrayList choices = GetFieldChoices(field);
                                if (!global_column_values.Contains(field.InternalName))
                                    global_column_values.Add(field.InternalName, choices);
                                else
                                    global_column_values[field.InternalName] = choices;
                            }
                            else if (field.Type == SPFieldType.Boolean)
                            {
                                ArrayList choices = new ArrayList();
                                choices.Add("Yes");
                                choices.Add("No");
                                if (!global_column_values.Contains(field.InternalName))
                                    global_column_values.Add(field.InternalName, choices);
                                else
                                    global_column_values[field.InternalName] = choices;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error retrieving metadata fields: " + ex.Message);
            }
        }
        public static void EnumSitesToComboBox(SPWeb myweb,ComboBox mycombo)
        {
            try
            {
                mycombo.Items.Clear();
                mycombo.Items.Add(myweb.Url);
                foreach (SPWeb sub in myweb.Webs)
                {
                    mycombo.Items.Add(sub.Url);
                }
                if (mycombo.Items.Count > 0)
                    mycombo.SelectedIndex = 0;
                else
                {
                    throw new Exception("No SharePoint web sites were found on this web server.");
                }

            }
            catch (Exception ex)
            {

                throw ex;
            }

        }
        public static void EnumLibrariesToComboBox(SPWeb myweb,ComboBox mycombo)
        {
            try
            {
                SPListCollection col = myweb.GetListsOfType(SPBaseType.DocumentLibrary);

                mycombo.Items.Clear();
                foreach (SPList mylist in col)
                {
                    if (!mylist.Hidden == true)
                    {
                        mycombo.Items.Add(mylist.Title);
                    }
                }

                if (mycombo.Items.Count > 0)
                    mycombo.SelectedIndex = 0;
            }
            catch (Exception)
            {

                throw;
            }
        }
        public static void EnumContentTypesToComboBox(SPList mylib,ComboBox mycombo)
        {
            mycombo.Items.Clear();
            foreach (SPContentType ct in mylib.ContentTypes)
            {
                if (!ct.Hidden)
                    mycombo.Items.Add(ct.Name);
            }
            if (mycombo.Items.Count > 0)
                mycombo.SelectedIndex = 0;
        }
        public static void EnumFoldersToComboBox(SPList mylib,ComboBox mycombo)
        {
            try
            {
                mycombo.Items.Clear();
                mycombo.Items.Add("<root>");
                foreach (SPListItem myfolder in mylib.Folders)
                {
                    mycombo.Items.Add(myfolder.Url.Replace(mylib.Title + "/", ""));
                }

                if (mycombo.Items.Count > 0)
                    mycombo.SelectedIndex = 0;

            }
            catch (Exception)
            {

                throw;
            }
        }
        public static SPWeb GetWebFromUrl(Uri folderUri)
        {
            try
            {
                string relativeFolderUrl = folderUri.LocalPath;
                SPWeb web = null;
                SPSite site = new SPSite(folderUri.ToString());

                
                while (web == null)
                {
                    try
                    {
                        // Try to open web and get the ID. If the Url is invalid it will
                        // throw a FileNotFoundException
                        web = site.OpenWeb(relativeFolderUrl);
                        Guid g = web.ID; // Try to get Web Information
                    }
                    catch (FileNotFoundException)
                    {
                        // Set web to null to continue search
                        web = null;

                        // Remove the last segment of the url and try again
                        relativeFolderUrl = relativeFolderUrl.Substring(0, relativeFolderUrl.LastIndexOf("/"));
                    }
                }

                return web;
            }
            catch (Exception ex)
            {
                throw new Exception("Error retrieving web for " + folderUri + ":" + ex.Message);
            }

        }
        public static string WriteErrFile(StringBuilder Report)
        {
            try
            {
                string errfile = string.Empty;
                if (Report.ToString() != string.Empty)
                {
                    errfile = System.Environment.CurrentDirectory + "\\ImportErrors_" + DateTime.Now.ToString("MMddyyhhmmss") + ".txt";
                    if (File.Exists(errfile) == true)
                    {
                        File.Delete(errfile);
                    }
                    File.WriteAllText(errfile, Report.ToString());

                }
                return errfile;
            }
            catch (Exception)
            {
                throw;
            }
        }
        public static bool ValidateFieldValue(SPList mylist, string content_type_name, string field_name, object myvalue)
        {
            bool ret = true;

            if (field_name == "FileLeafRef")
                goto Exit_Routine;

            SPField myfield;
            try
            {
                myfield = mylist.Fields.GetFieldByInternalName(field_name);
            }
            catch (Exception ex1)
            {
                try
                {
                    if (content_type_name != string.Empty)
                    {
                        SPContentType ct = mylist.ContentTypes[content_type_name];
                        myfield = ct.Fields.GetFieldByInternalName(field_name);
                    }
                    else
                    {
                        throw ex1;
                    }
                }
                catch (Exception ex2)
                {
                    throw ex2;
                }
            }

            if (myfield.Required)
            {
                if (myfield.DefaultValue == null)
                {
                    if (myvalue == null)
                    {
                        ret = false;
                        goto Exit_Routine;
                    }

                    if (myvalue.ToString().Trim() == string.Empty)
                    {
                        ret = false;
                        goto Exit_Routine;
                    }
                }
            }
            
            if (myfield.Type == SPFieldType.Choice || myfield.Type == SPFieldType.MultiChoice)
            {
                ArrayList choices = GetFieldChoices(myfield);
                if (myvalue != null)
                {
                    if (!choices.Contains(myvalue.ToString()))
                    {
                        ret = false;
                        goto Exit_Routine;
                    }
                }
                else
                {
                    ret = false;
                    goto Exit_Routine;
                }
            }           
        Exit_Routine:
            return ret;
        }
        public static string CleanFilename(string filename)
        {
            try
            {
                //"  -  Quotation mark          #  -  Number sign 
                //%  -  Percent Sign            &  -  Ampersand 
                //*  -  Asterisk                :  -  Colon 
                //<  -  Less than Symbol        >  -  Greater than Symbol 
                //?  -  Question Mark           \  -  Backslash 
                //{  -  Left Brace              }  -  Right Brace 
                //|  -  Pipe                    ~  -  Tilde 
                ///  -  Slash 

                string ret = Regex.Replace(filename, @"[\\/:*?""<>|#{}%~&]", "");
                ret = ret.Replace("%20", " ");
                if (ret.Length > 128)
                    ret = ret.Substring(0, 128);

                if (ret.StartsWith("."))
                    ret = ret.Substring(1);

                if (ret.EndsWith("."))
                    ret = ret.Substring(0,ret.Length - 1);

                return ret;
            }
            catch (Exception)
            {
                
                throw;
            }
        }

    }
}